package com.easylinkin.linkappapi.investigation.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.common.constant.CommonConstant;
import com.easylinkin.linkappapi.common.exceptions.BusinessException;
import com.easylinkin.linkappapi.common.service.CommonService;
import com.easylinkin.linkappapi.common.utils.DateUtil;
import com.easylinkin.linkappapi.investigation.entity.InvestigationTask;
import com.easylinkin.linkappapi.investigation.entity.InvestigationTaskModel;
import com.easylinkin.linkappapi.investigation.entity.InvestigationTaskModelContent;
import com.easylinkin.linkappapi.investigation.mapper.InvestigationTaskModelMapper;
import com.easylinkin.linkappapi.investigation.service.InvestigationTaskModelContentService;
import com.easylinkin.linkappapi.investigation.service.InvestigationTaskModelService;
import com.easylinkin.linkappapi.investigation.service.InvestigationTaskService;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import com.easylinkin.linkappapi.security.entity.LinkappUser;
import com.easylinkin.linkappapi.taskscheduler.constant.JobEntityConstant;
import com.easylinkin.linkappapi.taskscheduler.entity.JobEntity;
import com.easylinkin.linkappapi.taskscheduler.service.JobEntityService;
import com.easylinkin.linkappapi.taskscheduler.service.TaskSchedulerService;
import org.apache.commons.lang3.StringUtils;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 排查任务模板 服务实现类
 * </p>
 *
 * @author TongJie
 * @since 2021-04-15
 */
//禁止并发执行多个相同定义的JobDetail
@DisallowConcurrentExecution
@Service
public class InvestigationTaskModelServiceImpl extends ServiceImpl<InvestigationTaskModelMapper, InvestigationTaskModel> implements InvestigationTaskModelService,Job {
    private static final Logger LOGGER = LoggerFactory.getLogger(InvestigationTaskModelServiceImpl.class);
    @Resource
    LinkappUserContextProducer linkappUserContextProducer;
    @Resource
    private CommonService commonService;
    @Resource
    InvestigationTaskModelContentService investigationTaskModelContentService;
    @Resource
    TaskSchedulerService taskSchedulerService;
    @Resource
    JobEntityService jobEntityService;
    @Resource
    InvestigationTaskService investigationTaskService;

    private static final String PREFIX = "investigation";

    private static final String PREFIXMODEL="investigationModel";

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateInvestigationTaskModel(InvestigationTaskModel investigationTaskModel){
        //检查效验
        validParamRequiredUpdate(investigationTaskModel);
        validParamFormatUpdate(investigationTaskModel);
        InvestigationTaskModel originInvestigationTaskModel=getById(investigationTaskModel.getId());
        Assert.notNull(originInvestigationTaskModel,"原排查任务不存在");
        //获取租户
        LinkappUser linkappUser = linkappUserContextProducer.getNotNullCurrent();
        investigationTaskModel.setTenantId(linkappUser.getTenantId());
        //检查重复名称
        validRepeat(investigationTaskModel);
        //添加转换表达式
        timeFormatConversion(investigationTaskModel);
        commonService.setModifyInfo(investigationTaskModel);
        updateById(investigationTaskModel);
        //添加排查内容
        List<InvestigationTaskModelContent>  investigationTaskModelContentList=investigationTaskModel.getInvestigationTaskModelContentList();
        Assert.notEmpty(investigationTaskModelContentList, "排查内容不能为空");
        QueryWrapper<InvestigationTaskModelContent> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("investigation_task_model_id",investigationTaskModel.getId());
        investigationTaskModelContentService.remove(queryWrapper);
        //赋值
        int i=0;
        Date  createDate=new Date();
        for (InvestigationTaskModelContent investigationTaskModelContent:  investigationTaskModelContentList){
            investigationTaskModelContent.setInvestigationTaskModelId(investigationTaskModel.getId());
            investigationTaskModelContent.setTenantId(linkappUser.getTenantId());
            investigationTaskModelContent.setCreator(String.valueOf(linkappUser.getId()));
            investigationTaskModelContent.setCreateTime(createDate);
            investigationTaskModelContent.setModifyTime(createDate);
            investigationTaskModelContent.setModifier(String.valueOf(linkappUser.getId()));
            //序号
            investigationTaskModelContent.setSortNo(i);

            i++;
        }
        investigationTaskModelContentService.saveBatch(investigationTaskModelContentList);
        //插入定时任务
        investigationTaskModel.setStatus(originInvestigationTaskModel.getStatus());
        this.saveTask(investigationTaskModel);
        return true;
    }

    /**
     * 插入定时任务
     * */
    private void saveTask(InvestigationTaskModel investigationTaskModel){
        JobEntity jobEntity=new JobEntity();
        Date date = new Date();
        String jobGroup = PREFIX +"_"+ investigationTaskModel.getTenantId();
        //尽量使得任务名称唯一 以防根据名称执行 会执行到多个任务
        String jobName = PREFIXMODEL +"_"+investigationTaskModel.getId();
        //查询原有Job
        QueryWrapper<JobEntity> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("job_name",jobName);
        queryWrapper.eq("job_group",jobGroup);
        JobEntity originJobEntity=jobEntityService.getOne(queryWrapper);
        if(originJobEntity != null){
            jobEntity=originJobEntity;
        }
        jobEntity.setJobGroup(jobGroup);
        jobEntity.setJobName(jobName);
        jobEntity.setCronExpression(investigationTaskModel.getCycleCron());
        jobEntity.setJobStatus(String.valueOf(investigationTaskModel.getStatus()));
        jobEntity.setStartDate(investigationTaskModel.getStartTime());
        jobEntity.setEndDate(investigationTaskModel.getEndTime());

        jobEntity.setCreateTime(date);
        jobEntity.setModifyTime(date);
        jobEntity.setJobClassName(this.getClass().getName());
        //不立即运行
        jobEntity.setIsNowRun(JobEntityConstant.IsNowRunEnum.NO.getType());
        JSONObject parmObject = new JSONObject();
        parmObject.put("investigationTaskModelId",investigationTaskModel.getId());
        parmObject.put("startTime",investigationTaskModel.getStartTime());
        parmObject.put("endTime",investigationTaskModel.getEndTime());
        parmObject.put("cycle",investigationTaskModel.getCycle());
        setJobEntityDefaultProperty(jobEntity);
        jobEntity.setParams(parmObject.toString());
        taskSchedulerService.saveOrUpdateTaskSetStartTime(jobEntity);
    }

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        JobDetail jobDetail = jobExecutionContext.getJobDetail();
        String jobName = jobDetail.getKey().getName();
        String jobGroup = jobDetail.getKey().getGroup();
        LOGGER.info("intelligent-定时任务，任务分组：{}，任务名称：{}，任务触发时间：{}",
                jobGroup, jobName, DateUtil.getYYYYMMDDHHMMSSDate(new Date()));

        String parmString = jobDetail.getJobDataMap().getString("params");
        InvestigationTask investigationTask=new InvestigationTask();
        try{
            JSONObject  jsonObject = (JSONObject) JSON.parse(parmString);
            Long investigationTaskModelId=jsonObject.getLong("investigationTaskModelId");
            Date startTime=jsonObject.getDate("startTime");
            Date endTime=jsonObject.getDate("endTime");
            Float cycle=jsonObject.getFloat("cycle");
            if(investigationTaskModelId == null || startTime == null || cycle == null || cycle == 0){
                return;
            }
            Long dateTime = System.currentTimeMillis();
            Long day=(dateTime - startTime.getTime()) / 1000 / 60 / 60 / 24;
            if(day % cycle != 0){
                return;
            }
            investigationTask.setInvestigationTaskModelId(investigationTaskModelId);
            investigationTaskService.addTaskByTaskModel(investigationTask);
            day=(endTime.getTime() - dateTime) / 1000 / 60 / 60 / 24;
            //剩下时间不足一周期，删除定时任务
            if(day <= cycle){
                //根据job_name和job_group删除，条件唯一
                QueryWrapper<JobEntity> qw=new QueryWrapper<>();
                qw.eq("job_name",jobName);
                qw.eq("job_group",jobGroup);
                JobEntity jobEntity=jobEntityService.getOne(qw);
                taskSchedulerService.remove(jobEntity);
            }
        }catch(Exception e) {
            LOGGER.info("解析告警变量有异常,终止告警通知,异常明细{}", e.getMessage());
            return;
        }
    }

    /**
     *  修改状态
     *  @author chenkaixuan
     *  @since 2021-04-15
     * */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateStatusInvestigationTaskModel(InvestigationTaskModel investigationTaskModel){
        Assert.notNull(investigationTaskModel, "参数为空");
        Assert.notNull(investigationTaskModel.getId(),"原排查任务不存在");
//        Assert.notNull(investigationTaskModel.getStatus(), "状态不为空！");
        InvestigationTaskModel originInvestigationTaskModel=getById(investigationTaskModel.getId());
        Assert.notNull(originInvestigationTaskModel,"原排查任务不存在");
        //这里只修改状态，用原数据去修改
        // 状态取反   status = 1; b= 1 != 0; status = flase?0:1
        boolean b=originInvestigationTaskModel.getStatus()!=CommonConstant.ZERO;
        originInvestigationTaskModel.setStatus(b?CommonConstant.ZERO:CommonConstant.ONE);
        commonService.setModifyInfo(originInvestigationTaskModel);
        updateById(originInvestigationTaskModel);
        //修改定时任务
        this.updateJobStatus(originInvestigationTaskModel);
        return true;
    }

    private void updateJobStatus(InvestigationTaskModel investigationTaskModel){
        QueryWrapper<JobEntity> qw = new QueryWrapper();
        //qw.eq("id", jobEntityIds);
//        qw.eq("job_status", JobStatusEnum.ON.getType());
        qw.eq("job_name",PREFIXMODEL +"_"+ investigationTaskModel.getId());
        qw.eq("job_group",PREFIX +"_"+ investigationTaskModel.getTenantId());
        qw.ne("job_status", investigationTaskModel.getStatus());
        qw.eq("delete_state",1);
        List<JobEntity> jobEntities = jobEntityService.list(qw);
        Date date=new Date();
        for (JobEntity jobEntity : jobEntities) {
            jobEntity.setJobStatus(String.valueOf(investigationTaskModel.getStatus()));
            jobEntity.setModifyTime(date);
            taskSchedulerService.saveOrUpdateTaskSetStartTime(jobEntity);
        }
    }

    /**
     *  单个查询
     *  @author chenkaixuan
     *  @since 2021-04-15
     * */
    @Override
    public  InvestigationTaskModel getInvestigationTaskModel(Long id){
        Assert.notNull(id,"参数为空");
        InvestigationTaskModel originInvestigationTaskModel=getById(id);
        Assert.notNull(originInvestigationTaskModel,"排查任务不存在");
        List<InvestigationTaskModelContent> investigationTaskModelContentList= investigationTaskModelContentService.listByInvestigationTaskModelId(originInvestigationTaskModel.getId());
        originInvestigationTaskModel.setInvestigationTaskModelContentList(investigationTaskModelContentList);
        return originInvestigationTaskModel;
    }

    /**
     *  分页查询
     *  @author chenkaixuan
     *  @since 2021-04-15
     * */
    @Override
    public IPage<InvestigationTaskModel> getInvestigationTaskModelPage(Page page, InvestigationTaskModel investigationTaskModel) {
        return baseMapper.selectPage(page,getQueryWrapperConstructors(investigationTaskModel));
    }

    /**
     *  分页查询
     *  @author chenkaixuan
     *  @since 2021-04-20
     * */
    @Override
    public List<InvestigationTaskModel> getInvestigationTaskModelAll() {
        QueryWrapper<InvestigationTaskModel> qw=new QueryWrapper<>();
        qw.select("id","name");
        qw.eq("tenant_id", linkappUserContextProducer.getNotNullCurrent().getTenantId());
        qw.orderByDesc("start_time","end_time");
        return baseMapper.selectList(qw);
    }

    /**
     * 新增
     *  @author chenkaixuan
     *  @since 2021-04-15
     * */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addInvestigationTaskModel(InvestigationTaskModel investigationTaskModel){
        //检查效验
        validParamRequired(investigationTaskModel);
        validParamFormat(investigationTaskModel);
        //获取租户
        LinkappUser linkappUser = linkappUserContextProducer.getNotNullCurrent();
        investigationTaskModel.setTenantId(linkappUser.getTenantId());
        //检查重复名称
        validRepeat(investigationTaskModel);
        //创建时间，创建人
        commonService.setCreateAndModifyInfo(investigationTaskModel);
        //启用
        investigationTaskModel.setStatus(CommonConstant.ONE);
        //保存
        save(investigationTaskModel);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteBatch(List<InvestigationTaskModel> investigationTaskModelList) {
        Assert.notEmpty(investigationTaskModelList, "参数为空");
        List<Long> ids = investigationTaskModelList.stream().map(InvestigationTaskModel::getId).collect(Collectors.toList());
        //检查排查任务详情，查看任务是否正在使用中
       String tenantId=linkappUserContextProducer.getNotNullCurrent().getTenantId();
        QueryWrapper<InvestigationTask> queryWrapper=new QueryWrapper<>();
        queryWrapper.in("investigation_task_model_id",ids);
        queryWrapper.eq("tenant_id",tenantId);
        int count = investigationTaskService.count(queryWrapper);
        if (count > 0) {
            throw new BusinessException("要删除的任务模板正在被使用中，不允许删除");
        }
        //删除模板
        removeByIds(ids);
        //删除任务模板下面的排查内容
        investigationTaskModelContentService.deleteByInvestigationTaskModelIds(ids);
        //删除定时任务
        String jobGroup = PREFIX +"_"+ tenantId;
        //尽量使得任务名称唯一
        List<String> jobNames=ids.stream().map(i->PREFIXMODEL +"_").collect(Collectors.toList());
        //查询原有Job
        QueryWrapper<JobEntity> qw=new QueryWrapper<>();
        qw.in("job_name",jobNames);
        qw.eq("job_group",jobGroup);
        List<JobEntity> jobEntities=jobEntityService.list(qw);
        for (JobEntity jobEntity : jobEntities) {
            taskSchedulerService.remove(jobEntity);
        }
    }

    /**
     * 校验重复
     */
    private void validRepeat(InvestigationTaskModel investigationTaskModel) {
        QueryWrapper<InvestigationTaskModel> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name", investigationTaskModel.getName());
        queryWrapper.eq("tenant_id", investigationTaskModel.getTenantId());
        List<InvestigationTaskModel> list = baseMapper.selectList(queryWrapper);
        if (list.size() == 0) {
            return;
        }
        if (list.size() > 1) {
            throw new BusinessException("排查任务模板名称有重复");
        }
        if (investigationTaskModel.getId() == null) {
            throw new BusinessException("排查任务模板名称已存在");
        }
        if (!investigationTaskModel.getId().equals(list.get(0).getId())) {
            throw new BusinessException("排查任务模板名称已存在");
        }

    }

    /**
     * 校验参数必填
     */
    private void validParamRequiredUpdate(InvestigationTaskModel investigationTaskModel){
        //非空判断
        Assert.notNull(investigationTaskModel, "参数为空");
        Assert.isTrue(StringUtils.isNotBlank(investigationTaskModel.getName()), "名称为空");
        Assert.notNull(investigationTaskModel.getStartTime(),"开始时间为空");
        Assert.notNull(investigationTaskModel.getEndTime(),"结束时间为空");
        Assert.notNull(investigationTaskModel.getCycle(),"周期为空");
        Assert.notNull(investigationTaskModel.getExecuteTime(),"执行时间为空");
        Assert.notNull(investigationTaskModel.getPeriod(),"时长为空");
    }
    /**
     * 校验参数必填
     */
    private void validParamRequired(InvestigationTaskModel investigationTaskModel) {
        Assert.notNull(investigationTaskModel, "参数为空");
        Assert.isTrue(StringUtils.isNotBlank(investigationTaskModel.getName()), "名称为空");
    }
    /**
     * 校验参数格式
     */
    private void validParamFormatUpdate(InvestigationTaskModel investigationTaskModel){
        Assert.isTrue(investigationTaskModel.getName() == null || investigationTaskModel.getName().length() <= 50, "名称超长");
        Assert.isTrue(investigationTaskModel.getDescription() == null || investigationTaskModel.getDescription().length() <= 225, "说明超长");
        long currentTimeMillis=System.currentTimeMillis();
        //结束时间小于当前时间 处理
        Assert.isTrue(investigationTaskModel.getEndTime().getTime()> currentTimeMillis,"结束时间需大于当前时间");
        //开始时间大于结束时间 处理
        Assert.isTrue(investigationTaskModel.getStartTime().getTime()< investigationTaskModel.getEndTime().getTime(),"开始时间需小于结束时间");
        Long day=(investigationTaskModel.getEndTime().getTime() - investigationTaskModel.getStartTime().getTime()) / 1000 / 60 /60 /24;
        Assert.isTrue(investigationTaskModel.getCycle() <= day,"周期数过大");
    }
    /**
     * 校验参数格式
     */
    private void validParamFormat(InvestigationTaskModel investigationTaskModel) {
        Assert.isTrue(investigationTaskModel.getName() == null || investigationTaskModel.getName().length() <= 50, "名称超长");
        Assert.isTrue(investigationTaskModel.getDescription() == null || investigationTaskModel.getDescription().length() <= 225, "说明超长");
    }

    /**
     * 将时间转换为表达式
     * */
    private static void timeFormatConversion(InvestigationTaskModel investigationTaskModel){
        investigationTaskModel.setCycleCron("0 0 2 * * ? *");
    }

    /**
     * 构造查询条件
     * */
    private QueryWrapper<InvestigationTaskModel>  getQueryWrapperConstructors(InvestigationTaskModel investigationTaskModel){
        QueryWrapper<InvestigationTaskModel> queryWrapper=new QueryWrapper<>();
        if (StringUtils.isNotEmpty(investigationTaskModel.getName())) {
            queryWrapper.like("name", investigationTaskModel.getName());
        }
        if(investigationTaskModel.getStatus() != null){
            queryWrapper.eq("status",investigationTaskModel.getStatus());
        }

        if(investigationTaskModel.getStartTime() != null && investigationTaskModel.getEndTime() != null){
            //查询开始时间小于等于开始时间
            //查询结束时间大于等于开始时间
            queryWrapper.ge("start_time",investigationTaskModel.getStartTime());
            queryWrapper.le("start_time",investigationTaskModel.getEndTime());
            //queryWrapper.ge("end_time",investigationTaskModel.getStartTime());
        }
        queryWrapper.eq("tenant_id", linkappUserContextProducer.getNotNullCurrent().getTenantId());
//        queryWrapper.orderByDesc("start_time","end_time");
        queryWrapper.orderByDesc("modify_time", "create_time");
        return queryWrapper;
    }
    @Override
    public List<InvestigationTaskModel> getInvestigationTaskModelWithContents(InvestigationTaskModel investigationTaskModel) {
//        List<InvestigationTaskModel>  investigationTaskModelList=baseMapper.selectList(getQueryWrapperConstructors(investigationTaskModel));
//        if(investigationTaskModelList == null || investigationTaskModelList.size()<=0){
//            return investigationTaskModelList;
//        }
//        List<InvestigationTaskModelContent> investigationTaskModelContentList=null;
//        for(InvestigationTaskModel originInvestigationTaskModel : investigationTaskModelList){
//            investigationTaskModelContentList= investigationTaskModelContentService.listByInvestigationTaskModelId(originInvestigationTaskModel.getId());
//            originInvestigationTaskModel.setInvestigationTaskModelContentList(investigationTaskModelContentList);
//        }
//        return investigationTaskModelList;
        return baseMapper.getInvestigationTaskModelWithContents(investigationTaskModel);
    }


    /**
     * 如果某些属性为空 给设置默认值
     */
    private void setJobEntityDefaultProperty(JobEntity jobEntity) {

        if (StringUtils.isEmpty(jobEntity.getJobTaskType())) {
            jobEntity.setJobTaskType(JobEntityConstant.JobTaskTypeEnum.API.getType());
        }
        if (StringUtils.isEmpty(jobEntity.getJobType())) {
            jobEntity.setJobType(JobEntityConstant.JobTypeEnum.CYCLE.getType());
        }
        if (StringUtils.isEmpty(jobEntity.getIsNowRun())) {
            jobEntity.setIsNowRun(JobEntityConstant.IsNowRunEnum.YES.getType());
        }
    }
}
